// inventory.js
import { Engine } from "../engine";
import { DateUtil } from '../../utils/dateUtil';
import { CommonOrderStatus, OrderSortType, DocType } from "../common/docDefinition";
import { WareHouse } from "./warehouse";
import { SubCommodity } from "../commodity/subCommodity";
import { CsDouble } from "../common/csDouble";
import { CsFundDouble } from "../common/csFundDouble";
import { MeasurementUnit } from "../basicData/measurementUnit";
import { DocBase } from "../common/docBase";
import { OrderUtil } from "../../utils/orderUtil";
import { Util } from "../../utils/util";
import { TargetObject, TargetObjectType } from "../targetOrg/targetObject";
import { InventoryType } from "./inventoryType";
import { Definition } from "../common/definition";

// 商品出入库类型
export const InventoryInOutType = {
    Out: 0,    // 出库
    In: 1,     // 入库
    Init: 2,   // 期初
    Sheet: 3,  // 盘点
    Uknown: 4,  // 未知

    parseInOutType(jsonValue) {
        try {
            // 直接通过键名访问，避免 Object.values 的问题
            if (jsonValue === 0) return InventoryInOutType.Out;
            if (jsonValue === 1) return InventoryInOutType.In;
            if (jsonValue === 2) return InventoryInOutType.Init;
            if (jsonValue === 3) return InventoryInOutType.Sheet;
            return InventoryInOutType.Uknown;
        } catch (e) {
            console.error("Unknown Inventory inout data:", jsonValue);
            return InventoryInOutType.Uknown;
        }
    }
};



/// 商品批次
export class CommodityBatch {
    /** 无折扣 */
    static constNoDiscount = 100;
    constructor({
        commodity, // SubCommodity
        count = null,   /// 数量  CsDouble      
        countAfterDiscount = null,  // 折后数量，用于贵金属或是其他折扣回收
        batchPrice,   // CsFundDouble
        singlePrice,  // CsFundDouble
        referPrice,   // CsFundDouble  参考价
        /** @type {CsDouble} 折扣 0.00-100.00 (0全折扣，100无折扣) */
        discount = CommodityBatch.constNoDiscount,
        maxCount = null,   /// 最大入库量/最大出库数量
        inventoryCount = 0,   // 库存总数量        
        availableCount = 0,  // 可用库存总量
        id = "", /// 批次ID,
        pendingBatch = null,  // CommodityPendingBatch

        // 关联单据信息
        orderId,              // 所属单据 ID
        operateDate,          // 所属单据业务日期
        targetObjName,        // 所属单据往来单位名称
        targetObjId,            // 所属单据往来单位ID
        orderRemark,            // 所属单据备注
    }) {
        this.commodity = commodity;
        this._count = count;
        this._countAfterDiscount = countAfterDiscount;
        this._batchPrice = batchPrice;
        this._singlePrice = singlePrice;
        this._referPrice = referPrice,   // CsFundDouble  参考价
            this._discount = new CsDouble(discount, Definition.gConstDiscountRatePrecision);
        this._maxCount = maxCount;
        this.inventoryCount = new CsDouble(inventoryCount);
        this.availableCount = new CsDouble(availableCount);
        this.id = id;
        this.pendingBatch = pendingBatch;    /// 入库处理时采用  CommodityPendingBatch
        this.cost = null;   /// 成本，后台计算
        this.selected = false;   /// for ui

        this.orderId = orderId;
        this.operateDate = operateDate;
        this.targetObjName = targetObjName;
        this.targetObjId = targetObjId;
        this.orderRemark = orderRemark;
    }

    // com SubCommodity
    static forCommodityIn(com) {
        return new CommodityBatch({
            commodity: com,
            count: new CsDouble(1),
            batchPrice: com.purchasePrice,
            singlePrice: com.purchasePrice,
            inventoryCount: 0,
            availableCount: 0,
        });
    }

    // aPendingBatch CommodityPendingBatch
    static fromCommodityPendingBatch(aPendingBatch) {
        return new CommodityBatch({
            id: "",
            count: new CsDouble(0),
            commodity: aPendingBatch.commodity,
            batchPrice: aPendingBatch.batchPrice,
            singlePrice: aPendingBatch.singlePrice,
            maxCount: aPendingBatch.unhandledCount,
            pendingBatch: aPendingBatch,
            inventoryCount: 0,
            availableCount: 0,
        });
    }

    // batchSheet CommodityBatchSheet
    static fromCommodityBatchSheet(batchSheet) {
        return new CommodityBatch({
            id: batchSheet.id,
            commodity: batchSheet.commodity,
            pendingBatch: null,
            availableCount: batchSheet.count.value,
            batchPrice: new CsFundDouble(0),
            singlePrice: new CsFundDouble(0),
            count: batchSheet.adjustCount || new CsDouble(0),
            inventoryCount: batchSheet.count.value,
        });
    }

    static clone(batch) {
        const cloned = new CommodityBatch({
            id: batch.id,
            count: batch._count,
            countAfterDiscount: batch._countAfterDiscount,
            batchPrice: batch._batchPrice,
            singlePrice: batch._singlePrice,
            discount: batch._discount,
            maxCount: batch._maxCount,
            inventoryCount: batch.inventoryCount.value,
            availableCount: batch.availableCount.value,
            pendingBatch: batch.pendingBatch,
            commodity: SubCommodity.clone(batch.commodity),
            referPrice: batch._referPrice,
            orderId: batch.orderId
        });
        return cloned;
    }


    /// 拷贝 batch CommodityBatch
    copy(batch) {
        this.id = batch.id;
        this._count = batch._count;
        this._batchPrice = batch._batchPrice;
        this._singlePrice = batch._singlePrice;
        this._maxCount = batch._maxCount;
        this.inventoryCount = batch.inventoryCount;
        this.availableCount = batch.availableCount;
        this.pendingBatch = batch.pendingBatch;
        this._discount = batch._discount;
        this._countAfterDiscount = batch._countAfterDiscount;
        this._referPrice = batch._referPrice;
        this.orderId = batch.orderId;
    }

    // 是否支持贵金属交易模式
    get isMetalTradeBatch() {
        return !Util.isEmpty(this.commodity?.metalAccountTypeId);
    }

    get countOriginal() {
        return this._count;
    }

    get maxCount() {
        return this._maxCount;
    }

    get singlePrice() {
        return this._singlePrice;
    }

    get referPrice() {
        return this._referPrice;
    }

    set referPrice(referPrice) {
        this._referPrice = referPrice;
    }

    get batchPrice() {
        return this._batchPrice;
    }

    get count() {
        return this._count;
    }

    get countAfterDiscount() {
        return this._countAfterDiscount;
    }

    setCountAfterDiscount(count) {
        this._countAfterDiscount = count;
    }

    // 如果discount = 100.0 则无折扣
    // 如果discount = 750.0, 折后重量 = （discount - 0.2）* 原重量
    // ≥900	(纯度-2)/1000	2‰	高纯度金
    // 101-899	(纯度-3)/1000	3‰	普通纯度
    updateCountAfterDiscount() {

        if (this._count != null && this._discount != null) {
            // 如果discount = 100.0 则无折扣
            if (this._discount.value === 100) {
                this._countAfterDiscount = this._count;
            }
            // 如果discount ≥ 90.0, 折后重量 = 原重量 * (discount - 2) / 1000
            else if (this._discount.value >= 90.0) {
                this._countAfterDiscount = new CsDouble(
                    this._count.value * (this._discount.value - 0.2) / 100,
                    2, true, true
                );
            }
            // 如果discount = 750.0, 折后重量 = （discount - 2）/ 1000
            else if (this._discount.value == 75.0) {
                this._countAfterDiscount = new CsDouble(
                    this._count.value * (this._discount.value - 0.2) / 100,
                    2, true, true
                );
            }
            // 如果discount在101-899之间, 折后重量 = 原重量 * (discount - 3) / 1000
            else if (this._discount.value >= 10 && this._discount.value < 90) {
                this._countAfterDiscount = new CsDouble(
                    this._count.value * (this._discount.value - 0.3) / 100,
                    2, true, true
                );
            }
            // 其他情况按原逻辑处理 (discount为0-100之间的值)
            else {
                this._countAfterDiscount = null;
            }
        } else {
            this._countAfterDiscount = null;
        }
    }

    /** 折扣 CsDouble*/
    get discount() {
        return this._discount;
    }

    // value CsDouble
    set discount(value) {
        this._discount = new CsDouble(
            value.value,
            Definition.gConstDiscountRatePrecision
        );
        this.updateCountAfterDiscount();
    }

    // count CsDouble
    setCount(count) {
        let ret = null;
        if (count != null) {
            if (count.gte(new CsDouble(0)) && this._maxCount == null) {
                this._count = count;
                this._batchPrice = this._singlePrice?.mul(count);
                ret = this._count;
            } else if (count.gte(new CsDouble(0)) &&
                this._maxCount != null &&
                count.lte(this._maxCount)) {
                this._count = count;
                this._batchPrice = this._singlePrice?.mul(count);
                ret = this._count;
            }
        } else {
            this._count = null;
            this._batchPrice = null;
            ret = this._count;
        }

        this.updateCountAfterDiscount();
        return ret;
    }


    // subCount CsDouble
    subtractCount(subCount) {
        if (subCount.toDouble() > 0) {
            this._count = this.count.sub(subCount);
            this._count = this.count.toDouble() >= 0 ? this.count : new CsDouble(0);
        }
        this._batchPrice = this._singlePrice.mul(this.count);
        this.updateCountAfterDiscount();
        return this.count;
    }

    addCount(subCount) {
        // 如果 count 为空，设置count
        if (this._count == null) {
            this._count = new CsDouble(0);
        }
        if (subCount.toDouble() > 0) {
            this._count = this.count.add(subCount);
            if (this._maxCount != null) {
                this._count = this.count.gt(this._maxCount) ? this._maxCount : this.count;
            }
        }
        this._batchPrice = this._singlePrice?.mul(this.count);
        this.updateCountAfterDiscount();
        return this.count;
    }

    addAll() {
        if (this._maxCount != null) {
            this._count = this._maxCount;
            this._batchPrice = this._singlePrice?.mul(this.count);
        }
        this.updateCountAfterDiscount();
        return this.count;
    }



    // 返回 CsFundDouble
    setSinglePrice(price) {
        if (price.gte(new CsFundDouble(0))) {
            this._singlePrice = price;
            if (this._count != null) {
                this._batchPrice = this._singlePrice.mul(this._count);
            }
            return this._singlePrice;
        }
        return null;
    }

    setBatchPrice(price) {
        if (price.gte(new CsFundDouble(0))) {
            this._batchPrice = price;
            if (this._count?.gt(new CsDouble(0)) ) {
                this._singlePrice = this._batchPrice.div(this.count);
            }
            return this._batchPrice;
        }
        return null;
    }

    /// 有源入库单编辑时更新batch 信息
    /// 未处理数量需要添加上当前数量，编辑已有有源出入库单据时，已有单据的数量也是未处理数量
    /// aPendingBatch CommodityPendingBatch
    initCommodityPendingBatchForEdit(aPendingBatch) {
        this._batchPrice = aPendingBatch.batchPrice;
        this._singlePrice = aPendingBatch.singlePrice;

        // 未处理数量需要添加上当前数量，编辑已有有源出入库单据时，已有单据的数量也是未处理数量
        this._maxCount = aPendingBatch.unhandledCount;
        this.pendingBatch = aPendingBatch;
        this.availableCount = new CsDouble(0);
        this.inventoryCount = new CsDouble(0);
    }

    static fromJson(json) {
        const batch = new CommodityBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["inoutStore"], 0),
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commondityId']),
                unit: MeasurementUnit.fromJsonValue({
                    id: json['commodityUnitId'],
                    name: json['commodityUnit'],
                    supportDecimal: json['unitDecimalSupport']
                }),
                purchasePrice: Util.jsonToDouble(json['lineCostPrice'], 0),
                retailPrice: Util.jsonToDouble(json['lineRetailPrice'], 0),
                wholesalePrice: Util.jsonToDouble(json['lineTradePrice'], 0),
                imgs: Util.jsonToString(json['specImgs'])
            }),

            batchPrice: Util.jsonToCsFundDouble(json['inoutSumPrice'], 0),
            singlePrice: Util.jsonToCsFundDouble(json['inouttPrice'], 0),
            availableCount: 0,
            inventoryCount: 0,
            referPrice: Util.jsonToCsFundDouble(json['referPrice'], 0),


            // 业务单据数据
            orderId: Util.jsonToString(json['orderId']),
            operateDate: Util.jsonToDateTime(json['businessTime']),
            targetObjName: Util.jsonToString(json['objName']),
            targetObjId: Util.jsonToString(json['objId']),
            orderRemark: Util.jsonToString(json['orderRemark']),
        });
        // 采用汇算结算后的价格
        batch.cost = json['costAdjust'] == null ? null : Util.jsonToDouble(json['costAdjust'], 0);

        if (batch.count.value != CsDouble.zero().value) {
            batch.setSinglePrice(batch.batchPrice.div(batch.count));
        }

        return batch;
    }

    static fromInventoryTransferJson(json) {
        let batch = new CommodityBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["changeCount"], 0),
            batchPrice: Util.jsonToCsFundDouble(json['inoutSumPrice'], 0),
            singlePrice: Util.jsonToCsFundDouble(json['inouttPrice'], 0),
            availableCount: 0,
            inventoryCount: 0,
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commodityId']),
                unit: MeasurementUnit.fromJsonValue({
                    id: Util.jsonToString(json['unitId']),
                    name: Util.jsonToString(json['unitName']),
                    supportDecimal: Util.jsonToBool(json['decimalSupport'], false)
                }),
                purchasePrice: Util.jsonToDouble(json['lineCostPrice'], 0),
                retailPrice: Util.jsonToDouble(json['lineRetailPrice'], 0),
                wholesalePrice: Util.jsonToDouble(json['lineTradePrice'], 0),
                imgs: Util.jsonToString(json['specImgs']),
            }),

            // 业务单据数据
            orderId: Util.jsonToString(json['orderId']),
            operateDate: Util.jsonToDateTime(json['businessTime']),
            targetObjName: Util.jsonToString(json['objName']),
            targetObjId: Util.jsonToString(json['objId']),
            orderRemark: Util.jsonToString(json['orderRemark']),
        });

        if (batch.count.value != CsDouble.zero().value) {
            batch.setSinglePrice(batch.batchPrice.div(batch.count));
        }

        return batch;
    }

    static fromPurchaseSalesJson(json) {
        const batch = new CommodityBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["inoutStore"], 0),
            countAfterDiscount: Util.jsonToCsDouble(json["inoutStoreAfterDiscount"], 0),
            discount: Util.jsonToCsDouble(
                json.discount,
                CommodityBatch.constNoDiscount,
                Definition.gConstDiscountRatePrecision
            ),
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commondityId']),
                unit: MeasurementUnit.fromJsonValue({
                    // 修复后台命名不统一问题,导致salesquotation 向下拷贝丢失单位id
                    id: Util.jsonCommodityUnitoString(json),
                    name: Util.jsonToString(json['commodityUnit']),
                    supportDecimal: Util.jsonToBool(json['unitDecimalSupport'], false)
                }),
                purchasePrice: Util.jsonToDouble(json['lineCostPrice'], 0),
                retailPrice: Util.jsonToDouble(json['lineRetailPrice'], 0),
                wholesalePrice: Util.jsonToDouble(json['lineTradePrice'], 0),
                imgs: Util.jsonToString(json['specImgs']),
                metalAccountTypeId: Util.jsonToString(json.metalAccountTypeId, null),
                metalCode: Util.jsonToString(json.metalCode, null),
                isMetalSelf: Util.jsonToBool(json.isMetalSelf, false)
            }),

            batchPrice: Util.jsonToCsFundDouble(json['amountWithoutDiscountAndTax'], 0),
            singlePrice: Util.jsonToCsFundDouble(json['singlePrice'], 0),
            // 总库存数量
            inventoryCount: Util.jsonToDouble(json['sumCount'], 0),
            // 可用库存
            availableCount: Util.jsonToDouble(json['specCanStore'], 0),

            referPrice: Util.jsonToCsFundDouble(json['referPrice'], 0),


            // 业务单据数据
            orderId: Util.jsonToString(json['orderId']),
            operateDate: Util.jsonToDateTime(json['businessTime']),
            targetObjName: Util.jsonToString(json['objName']),
            targetObjId: Util.jsonToString(json['objId']),
            orderRemark: Util.jsonToString(json['orderRemark']),

        });

        if (batch.count.value != CsDouble.zero().value) {
            batch.setSinglePrice(batch.batchPrice.div(batch.count));
        }
        return batch;
    }

    // refining 
    static fromRefiningContract(json) {
        const batch = new CommodityBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["inoutStore"], 0),
            discount: Util.jsonToCsDouble(
                json.discount,
                CommodityBatch.constNoDiscount,
                Definition.gConstDiscountRatePrecision
            ),
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commondityId']),
                unit: MeasurementUnit.fromJsonValue({
                    // 修复后台命名不统一问题,导致salesquotation 向下拷贝丢失单位id
                    id: Util.jsonCommodityUnitoString(json),
                    name: Util.jsonToString(json['commodityUnit']),
                    supportDecimal: Util.jsonToBool(json['unitDecimalSupport'], false)
                }),
                purchasePrice: Util.jsonToDouble(json['lineCostPrice'], 0),
                retailPrice: Util.jsonToDouble(json['lineRetailPrice'], 0),
                wholesalePrice: Util.jsonToDouble(json['lineTradePrice'], 0),
                imgs: Util.jsonToString(json['specImgs']),
                metalAccountTypeId: Util.jsonToString(json.metalAccountTypeId, null),
                metalCode: Util.jsonToString(json.metalCode, null),
                isMetalSelf: Util.jsonToBool(json.isMetalSelf, false)
            }),

            batchPrice: Util.jsonToCsFundDouble(json['amount'], 0),
            singlePrice: Util.jsonToCsFundDouble(json['singlePrice'], 0),


            // 业务单据数据
            orderId: Util.jsonToString(json['orderId']),
            operateDate: Util.jsonToDateTime(json['businessTime']),
            targetObjName: Util.jsonToString(json['objName']),
            targetObjId: Util.jsonToString(json['objId']),
            orderRemark: Util.jsonToString(json['orderRemark']),
        });

        return batch;
    }

    /// 出入库明细时构造函数
    static fromInventoryRecordJson(json) {
        //console.log('CommodityBatch.fromInventoryRecordJson', json);
        let batch = new CommodityBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["optionStore"], 0),
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                code: Util.jsonToString(json["commodityCode"]),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commondityId']),
                unit: MeasurementUnit.fromJsonValue({
                    id: Util.jsonToString(json['commodityUnitId']),
                    name: Util.jsonToString(json['unitName']),
                    supportDecimal: Util.jsonToBool(json["decimalSupport"], false)
                }),
                purchasePrice: 0,
                retailPrice: 0,
                wholesalePrice: 0,
                imgs: Util.jsonToString(json['specImgs'])
            }),

            batchPrice: Util.jsonToCsFundDouble(json['sumPrice'], 0),
            singlePrice: Util.jsonToCsFundDouble(json['singlePrice'], 0),
            availableCount: 0,
            inventoryCount: 0,


            // 业务单据数据
            orderId: Util.jsonToString(json['orderId']),
            operateDate: Util.jsonToDateTime(json['businessTime']),
            targetObjName: Util.jsonToString(json['objName']),
            targetObjId: Util.jsonToString(json['objId']),
            orderRemark: Util.jsonToString(json['orderRemark']),
        });

        if (batch.count.value != CsDouble.zero().value) {
            batch.setSinglePrice(batch.batchPrice.div(batch.count));
        }
        return batch
    }
}


/// 出入库明细过滤条件
export class CommodityInoutRecordFilter {
    constructor({ storeId = null } = {}) {
        /// 规格商品ID
        this.subCommodityId = null;
        /// 规格商品编号
        this.code = null;
        /// 商品名称
        this.subCommodityName = null;
        /// 规格名称
        this.standName = null;
        /// 条码二维码
        this.qrCode = null;
        /// 往来单位名称
        this.targetObjName = null;
        /// 仓库
        this.wareHouse = null;
        /// 开始时间
        this.startDate = null;
        /// 结束时间
        this.endDate = null;
        /// 记录类型 InventoryInOutType
        this.recordType = null;

        /// 门店过滤
        this.storeId = storeId || Engine.profile?.filterStore?.id;
    }

    clear() {
        this.code = null;
        this.subCommodityName = null;
        this.standName = null;
        this.qrCode = null;
        this.targetObjName = null;
        this.wareHouse = null;
        this.startDate = null;
        this.endDate = null;
        this.recordType = null;
        this.subCommodityId = null;
    }

    static clone(filter) {
        const cloned = new CommodityInoutRecordFilter();
        cloned.code = filter.code;
        cloned.subCommodityName = filter.subCommodityName;
        cloned.standName = filter.standName;
        cloned.qrCode = filter.qrCode;
        cloned.targetObjName = filter.targetObjName;
        cloned.wareHouse = filter.wareHouse;
        cloned.startDate = filter.startDate;
        cloned.endDate = filter.endDate;
        cloned.recordType = filter.recordType;
        cloned.storeId = filter.storeId;
        cloned.subCommodityId = filter.subCommodityId;
        return cloned;
    }

    toJson() {
        const ret = {};

        if (this.code && this.code.length > 0) ret["c_lke_commodityCode"] = this.code;
        if (this.subCommodityName && this.subCommodityName.length > 0) {
            ret["c_lke_commodityName"] = this.subCommodityName;
        }
        if (this.standName && this.standName.length > 0) {
            ret["c_lke_specName"] = this.standName;
        }
        if (this.qrCode && this.qrCode.length > 0) {
            ret["c_lke_commodityBarcode"] = this.qrCode;
        }

        // 该语句一定位于上述其他商品属性过滤条件之后
        if (Object.keys(ret).length === 0 && this.subCommodityId != null) {
            ret["specId"] = this.subCommodityId;
        } else {
            this.subCommodityId = null;
        }

        if (this.targetObjName != null) ret["objName"] = this.targetObjName;

        if (this.startDate && this.endDate && this.endDate > this.startDate) {
            ret["gte_createTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
            ret["lte_createTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.startDate && !this.endDate) {
            ret["gte_createTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.endDate && !this.startDate) {
            ret["lte_createTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        }

        if (this.wareHouse != null) ret['storageId'] = this.wareHouse.id;

        if (this.recordType != null) {
            ret["optionType"] = Object.values(InventoryInOutType).indexOf(this.recordType);
        }

        if (this.storeId != null) {
            ret["storeId"] = this.storeId;
        }

        return ret;
    }
}

/// 出入库明细
export class InventoryInOutRecord {
    constructor({
        id,
        commodityBatch, //CommodityBatch
        wareHouse,  // WareHouse
        type,  // InventoryInOutType
        createTime,
        creator,  /// 创建人
        operationCode = "",   /// 操作编码
        isWithdraw = false
    }) {
        this.commodityBatch = commodityBatch;
        this.wareHouse = wareHouse;
        this.type = type;
        this.createTime = createTime;
        this.id = id;
        this.creator = creator;
        this.operationCode = operationCode;
        this.isWithdraw = isWithdraw;
    }

    static fromJson(json) {
        //console.log("inoutrecord from json:", json);
        return new InventoryInOutRecord({
            commodityBatch: CommodityBatch.fromInventoryRecordJson(json),
            wareHouse: new WareHouse({
                id: Util.jsonToString(json['storageId']),
                name: Util.jsonToString(json['storageName'])
            }),
            type: InventoryInOutType.parseInOutType(json['optionType']),
            createTime: Util.jsonToString(json['createTime']),
            id: Util.jsonToString(json['id']),
            creator: Util.jsonToString(json['creator']),
            isWithdraw: Util.jsonToBool(json['actionType'], false),
            operationCode: Util.jsonToString(json['optionSource'])
        });
    }
}

/// 出入库单过滤条件
export class InventoryFilter {
    constructor({ storeId = null } = {}) {
        /// 单号
        this.inventoryId = null;
        /// 单据标题
        this.inventoryTitle = null;
        /// CommonOrderStatus 对应code  状态 0 all, 1 未审核，2 已审核  for desktop and web
        this.status = null;
        /// 仓库 WareHouse
        this.wareHouse = null;
        /// 往来单位名称
        this.targetObjName = null;
        /// 规格商品名称
        this.subCommodityName = null;
        /// 开始时间
        this.startDate = null;
        /// 结束时间
        this.endDate = null;

        /// 创建开始时间
        this.createStartDate = null;
        /// 创建结束时间
        this.createEndDate = null;
        /// 排序方式,默认按创建时间排序
        this.sortType = OrderSortType.CreateTime;
        /// 门店过滤
        this.storeId = storeId || Engine.profile?.filterStore?.id;
    }

    clear() {
        this.inventoryId = null;
        this.inventoryTitle = null;
        this.wareHouse = null;
        this.targetObjName = null;
        this.subCommodityName = null;
        this.startDate = null;
        this.endDate = null;
        this.status = null;
    }

    static clone(filter) {
        const cloned = new InventoryFilter();
        cloned.inventoryId = filter.inventoryId;
        cloned.inventoryTitle = filter.inventoryTitle;
        cloned.wareHouse = filter.wareHouse;
        cloned.targetObjName = filter.targetObjName;
        cloned.subCommodityName = filter.subCommodityName;
        cloned.startDate = filter.startDate;
        cloned.endDate = filter.endDate;
        cloned.status = filter.status;
        cloned.sortType = filter.sortType;
        cloned.storeId = filter.storeId;
        return cloned;
    }

    toJson({ withState = false } = {}) {
        const ret = {};

        if (this.status != null && this.status === CommonOrderStatus.WaitReview.code && withState) {
            ret['a_orderStatus'] = 0;
        }
        if (this.status != null && this.status === CommonOrderStatus.Passed.code && withState) {
            ret['a_orderStatus'] = 1;
        }
        if (this.inventoryId != null && this.inventoryId.length > 0) {
            ret["a_lke_id"] = this.inventoryId;
        }
        if (this.inventoryTitle != null && this.inventoryTitle.length > 0) {
            ret["a_lke_orderTitle"] = this.inventoryTitle;
        }
        if (this.wareHouse != null) ret["d_storageId"] = this.wareHouse.id;
        if (this.targetObjName != null && this.targetObjName.length > 0) {
            ret["objName"] = this.targetObjName;
        }

        if (this.subCommodityName != null && this.subCommodityName.length > 0) {
            ret["specName"] = this.subCommodityName;
        }

        // 创建时间过滤
        if (this.createStartDate && this.createEndDate && this.createEndDate > this.createStartDate) {
            ret["a_gte_createTime"] = DateUtil.formatDate(this.createStartDate, "yyyy-MM-dd HH:mm:ss");
            ret["a_lte_createTime"] = DateUtil.formatDate(this.createEndDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.createStartDate && !this.createEndDate) {
            ret["a_gte_createTime"] = DateUtil.formatDate(this.createStartDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.createEndDate && !this.createStartDate) {
            ret["a_lte_createTime"] = DateUtil.formatDate(this.createEndDate, "yyyy-MM-dd HH:mm:ss");
        }

        // 业务时间过滤
        if (this.startDate && this.endDate && this.endDate > this.startDate) {
            ret["a_gte_businessTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
            ret["a_lte_businessTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.startDate && !this.endDate) {
            ret["a_gte_businessTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.endDate && !this.startDate) {
            ret["a_lte_businessTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        }

        if (this.sortType.code === OrderSortType.CreateTime.code) {
            ret["sort"] = "a.create_time desc";
        } else if (this.sortType.code === OrderSortType.OperationTime.code) {
            ret["sort"] = "a.business_time desc, a.create_time desc";
        }

        if (this.storeId != null) {
            ret["storeId"] = this.storeId;
        }

        return ret;
    }
}

/// 出入库单
export class Inventory extends DocBase {
    constructor({
        wareHouse,
        type,   // InventoryType 注意是 InventoryType 类型 不是 InventoryInOutType
        commodityBatch = null,  //  List<CommodityBatch>
        targetObject,
        inOutType, // InventoryInOutType


        // super param
        id,
        storeId,
        storeName,
        remark = "",
        operator = "",
        operatorId = "",
        docMaker = "",
        status = CommonOrderStatus.WaitReview,
        title = "",
        docCode = "",
        parentDocType = null,  // DocType
        parentDocCode = "",
        parentDocTitle = "",
        sourceDocType = null,  // DocType
        sourceDocCode = "",
        sourceDocTitle = "",

        /// 记录时间
        recordDate = null,

        // 业务记录时间
        operationDate = null,

    }) {
        super({
            id,
            storeId,
            storeName,
            title,
            docCode,
            status,
            docType: inOutType === InventoryInOutType.In ? DocType.RKD : DocType.CKD,
            parentDocType,
            parentDocCode,
            parentDocTitle,
            sourceDocCode,
            sourceDocType,
            sourceDocTitle,
            recordDateTime: recordDate,
            operateDateTime: operationDate,
            operator,
            operatorId,
            docMaker,
            remark
        });

        this._commmodityList = commodityBatch || [];
        this.targetObject = targetObject;
        this.wareHouse = wareHouse;
        this.type = type;
    }

    static empty(
        { inOutType, operator = "", operatorId = "", storeId = "", storeName = "" }
    ) {

        // 设置默认门店
        /*
        let store = Engine.profile.currentStore;
        if (storeId == "") {
            storeId = store.id;
            storeName = store.name;
        }
        */
        const inventory = new Inventory({
            inOutType: inOutType,
            operator,
            operatorId,
            storeId,
            storeName,

            /*
            targetObject: TargetObject.empty({
                objType: inOutType === InventoryInOutType.In
                    ? TargetObjectType.TSupplier
                    : TargetObjectType.TCustomer
            }),
            */


            commodityBatch: [],
            // type: InventoryType.empty(),
            type: OrderUtil.getDefaultInventoryType(inOutType),
            wareHouse: WareHouse.empty(),

            id: "",
            storeId,
            storeName,

        });

        inventory.wareHouse = OrderUtil.getOrderDefaultWarehouse({
            storeId: inventory.storeId,
            curWarehouse: inventory.wareHouse
        });
        // inventory.type.inOutType = inOutType;


        console.log("inventory empty", inventory);

        return inventory;
    }

    static clone(data) {

        let baseOrder = DocBase.clone(data);

        const instance = new Inventory({
            wareHouse: WareHouse.clone(data.wareHouse),
            type: InventoryType.clone(data.type),
            targetObject: TargetObject.clone(data.targetObject),
        });

        Object.assign(instance, baseOrder);

        for (let element of data._commmodityList) {
            instance._commmodityList.push(CommodityBatch.clone(element));
        }

        return instance;
    }

    // InventoryInOutType
    get inOutType() {
        if (this.docType.code === DocType.RKD.code) {
            return InventoryInOutType.In;
        } else if (this.docType.code === DocType.CKD.code) {
            return InventoryInOutType.Out;
        }
        return InventoryInOutType.Uknown;
    }

    get totalCount() {
        let count = new CsDouble(0);
        for (const element of this._commmodityList) {
            count = count.add(element.count);
        }
        return count;
    }

    /// 入库金额
    get inventoryFundMount() {
        let mount = new CsFundDouble(0);
        for (const element of this._commmodityList) {
            mount = mount.add(element.batchPrice);
        }
        return mount;
    }

    // /// 更新商品列表 List<CommodityBatch>
    updateCommodityList(list) {
        this._commmodityList = [...list];
    }

    /// 商品列表
    get commmodityList() {
        return [...this._commmodityList];
    }

    /// 清除商品列表
    clearCommodity() {
        this._commmodityList = [];
    }

    /// 插入 batch  CommodityBatch
    addCommodityBatch(batch) {
        this._commmodityList.push(batch);
    }

    /// 插入 batch 或是更新数量
    /// 没有该商品，添加，如果有则增加数量
    addOrUpdateCommodityBatch(batch) {
        const existCommodityList = this._commmodityList.filter(
            element => element.commodity.id === batch.commodity.id
        );
        if (existCommodityList.length === 0) {
            this._commmodityList.push(batch);
        } else {
            existCommodityList[0].addCount(new CsDouble(1));
        }
    }

    /// 删除batch CommodityBatch
    removeCommodityBatch(batch) {
        const index = this._commmodityList.indexOf(batch);
        if (index !== -1) {
            this._commmodityList.splice(index, 1);
            return true;
        }
        return false;
    }

    indexOfCommodityBatch(batch) {
        return this._commmodityList.indexOf(batch);
    }

    /// 替换
    replaceCommodityBatch(batch, newBatch) {
        const index = this._commmodityList.indexOf(batch);
        if (index >= 0) {
            this._commmodityList[index] = newBatch;
            return true;
        }
        return false;
    }

    /// 是否是多条记录
    isMultiRecord(batch) {
        return this._commmodityList.filter(
            element => element.commodity.id === batch.commodity.id
        ).length > 1;
    }

    /// 复制 注意调用对象，应该是 子类 todo
    resetForCopy({ removeParentAndSourceData = true }) {
        super.resetForCopy({ removeParentAndSourceData });
        for (const element of this._commmodityList) {
            element.id = "";
        }
    }

    /// 从待处理单复制
    static fromPendingInventory(data) {
        const inventory = new Inventory({
            wareHouse: data.wareHouse,
            type: data.type,
            targetObject: data.targetObject,
            inOutType: data.inOutType,
            id: "",
            storeId: data.storeId,
            storeName: data.storeName,
            title: "",
            docCode: "",
            status: CommonOrderStatus.WaitReview,
            //            docType: data.inOutType == InventoryInOutType.In  构造函数会根据 inOutType 构造
            //                ? DocType.RKD
            //                : DocType.CKD,
            parentDocType: data.docType,
            parentDocCode: data.docCode,
            parentDocTitle: data.title,
            // 出入库的源单据是待出入库的上级单据
            sourceDocCode: data.parentDocCode,
            sourceDocType: data.parentDocType,
            sourceDocTitle: data.parentDocTitle,
            operator: Engine.profile?.nickName,
            operatorId: Engine.profile?.id,
            docMaker: Engine.profile?.nickName,
            remark: ""
        });

        inventory._commmodityList = data.commmodityList.map(
            element => CommodityBatch.fromCommodityPendingBatch(element)
        );
        return inventory;
    }
    /// 有源出入库单据编辑时，与pending inventory 绑定
    /// pendingInventory 类型 PendingInventory
    initPengingInventory(pendingInventory) {
        this.sourceDocCode = pendingInventory.parentDocCode;
        this.sourceDocTitle = pendingInventory.parentDocTitle;
        this.sourceDocType = pendingInventory.parentDocType;

        for (const element of pendingInventory.commmodityList) {
            // step 1  查询是否有 batch 信息
            // 返回第一条匹配记录 batch 类型 CommodityBatch
            const batch = this._commmodityList.find(
                comBatch => comBatch.commodity.id === element.commodity.id
            );

            if (batch) {
                // 有batch 信息更新pending batch
                if (Util.isEmpty(this.id)) {
                    // 新建单据（拷贝场景）不用扣除出入库单本身数量
                    // 如果出入库单中的数量，超过待处理数量，已待处理数量为上限
                    if (batch.count.gt(element.unhandledCount)) {
                        batch.setCount(element.unhandledCount);
                    }
                } else {
                    // 减去当前已处理数量，已有处理数量本次也会处理，所以返回到待处理数量中
                    element.subtractCurHandleCount(batch.count);
                }
                // 更新待处理数量
                batch.initCommodityPendingBatchForEdit(element);
            } else {
                this._commmodityList.push(CommodityBatch.fromCommodityPendingBatch(element));
            }
        }
    }

    static fromJson(json) {
        let baseOrder = DocBase.fromJson(json);

        //console.log("inventory baseOrder from json:", baseOrder);

        const inventory = new Inventory({
            targetObject: TargetObject.fromJsonForOrders(json),

            wareHouse: new WareHouse({
                id: Util.jsonToString(json['storageId']),
                name: Util.jsonToString(json['storageName'])
            }),
            type: new InventoryType({
                id: "",
                name: Util.jsonToString(json['inoutTypeName']),
                code: Util.jsonToString(json['inoutTypeCode']),
                inOutType: InventoryInOutType.Uknown
            }),


            inOutType: json['docType'] === DocType.RKD.code
                ? InventoryInOutType.In
                : InventoryInOutType.Out,
        });

        Object.assign(inventory, baseOrder);

        inventory.type.inOutType = inventory.inOutType;
        inventory._commmodityList = (json['details'] || []).map(
            element => CommodityBatch.fromJson(element)
        );

        return inventory;
    }

    toJson() {
        const ret = super.toJson();
        ret['details'] = this._commmodityList.map(element => ({
            'commondityId': element.commodity.commodityId,
            'commondityUnitId': element.commodity.unit.id,
            'id': element.id,
            'inoutStore': element.count.value,
            'inoutSumPrice': element.batchPrice.value,
            'inouttPrice': element.singlePrice.value,
            'orderId': this.id,
            'specId': element.commodity.id
        }));

        ret['objId'] = this.targetObject.id;
        ret['storageId'] = this.wareHouse.id;
        ret['inoutTypeCode'] = this.type.code;

        return ret;
    }

}